package com.sidom.movieIndexer.util;

import java.util.Arrays;
import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import com.sidom.movieIndexer.domain.Movie;

/**
 * LoggingInterceptor. In case the normal logging does not provide enough
 * information.
 * 
 * @author Siebe
 */
@Aspect
public class LoggingInterceptor {
	/**
	 * The logger. Will be instantiated when executing a method.
	 */
	private Log log = null;
	
	/**
	 * Log the method signature and parameters when entering the method.
	 * Log errors thrown in these methods if nessecery.
	 * Log the return value.
	 * @param pjp The Proceeding join point.
	 * @return The return Object
	 * @throws Throwable Throws exception if an error occurs in the method.
	 */
	@Around("execution(* com.sidom.movieIndexer..*.*(..))")
	public Object log(final ProceedingJoinPoint pjp) throws Throwable {
		Object result = null;
		log = LogFactory.getLog(pjp.getTarget().getClass());
		if(log.isTraceEnabled()){
			log.trace("Entering method: " + pjp.getSignature() + " with argurments: " + Arrays.toString(pjp.getArgs()));
			printMoviesIfPresentInArgumentList(pjp.getArgs());
		}
		try{
			result = pjp.proceed();
		}catch(Throwable throwable){
			log.error("Error occured while executing method: " + pjp.getSignature() + ". Excpetion is: " + throwable);
			throw throwable;
		}
		if(log.isTraceEnabled()){
			log.trace("Leaving method: " + pjp.getSignature() + " with result: " + result);
		}
		return result;
	}

	/**
	 * Print the movies if present in one of the arguments.
	 * @param args The arguments of the method.
	 */
	private void printMoviesIfPresentInArgumentList(final Object[] args) {
		StringBuilder moviesFromCollection = new StringBuilder();
		for (Object object : args) {
			if(object instanceof Collection<?>){
				Collection<?> collection = (Collection<?>)object;
				for (Object objectFromCollection : collection) {
					if(objectFromCollection instanceof Movie){
						moviesFromCollection.append((Movie)objectFromCollection);
					}
				}
			}
		}
		log.trace("Movies present in one of the arguments: " + moviesFromCollection);
	}
}
